﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using GeneratorLib.DB.Schemas;

namespace Generator.Generators
{
    public partial class MVCController : GeneratorCodeBase
    {
        public MVCController()
        {
            InitializeComponent();
            this.GeneratorName = "MVC Controller Generator";
            AddToolItems();
        }

        private void AddToolItems()
        {
            ToolStripMenuItem item0 = new ToolStripMenuItem("List Controller") {Tag = 0};
            ToolStripMenuItem item1 = new ToolStripMenuItem("Edit Controller") { Tag = 1 };
            ToolStripMenuItem item2 = new ToolStripMenuItem("List and Edit") { Tag = 2 };
            //ToolStripMenuItem item2 = new ToolStripMenuItem("FillModelData");
            //item2.Tag = 2;
            //ToolStripMenuItem item3 = new ToolStripMenuItem("GetModelData");
            //item3.Tag = 3;
            //ToolStripMenuItem item4 = new ToolStripMenuItem("SelectList");
            //item4.Tag = 4;
            //ToolStripMenuItem item5 = new ToolStripMenuItem("FillInputData");
            //item5.Tag = 5;

            this.AddToolStripItem(item0);
            this.AddToolStripItem(item1);
            this.AddToolStripItem(item2);
            //this.AddToolStripItem(item3);
        }

        public override void Generate(ToolStripItem item)
        {
            base.Generate(item);

            //this.Table = MYSQLUtility.GetTableInfo(this.Connection, this.Table.TableName);
            txtCode.ResetText();
            CodeBuilder.Clear();
            AppendUsing();
            AppendNameSpaceStart();
            TableInfoAddin tableAddin = this.Connection.FindTableAddin(this.Table.TableName);
            AppandClassStart("Controller", "Controller", string.Format("{0}",tableAddin.TableDisplayName));
            switch (Convert.ToInt32(item.Tag))
            {
                case 0:
                    CreateListController();
                    break;
                case 1:
                    CreateEditController();
                    break;
                case 2:
                    CreateListController();
                    CreateEditController();
                    break;
            }

            AppandClassEnd();
            AppendNameSpaceEnd();
            txtCode.Text = CodeBuilder.ToString();
            txtCode.Refresh();
        }

        private void CreateListController()
        {
            CreateListPart();
            //createEditPart();
        }

        private void CreateEditController()
        {
            //TableInfoAddin tableAddin = this.Connection.FindTableAddin(this.Table.TableName);
            
            //AppendUsing();
            //AppendNameSpaceStart();
           // AppandClassStart("Controller", "Controller", string.Format("{0}", tableAddin.TableDisplayName));
            //createListPart();
            CreateEditPart();
            //AppandClassEnd();
            //AppendNameSpaceEnd();
        }

        #region ListPart
        private void CreateListPart()
        {
            CodeBuilder.AppendLine("        #region {0}",this.Table.ViewListName);
            CreateListPart01();
            CreateListPart02();
            CreateListPart03();
            if (!this.Table.IsMasterTable)
                CodeBuilder.AppendLine("        /*");

            CreateListPart04();
            
            if (!this.Table.IsMasterTable)
                CodeBuilder.AppendLine("        */");

            CodeBuilder.AppendLine("        #endregion");

        }

        private void CreateListPart01()
        {
            TableInfoAddin tableAddin = this.Connection.FindTableAddin(this.Table.TableName);
            
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        /// <summary>");
            CodeBuilder.AppendLine("        /// {0}一覧",tableAddin.TableDisplayName);
            CodeBuilder.AppendLine("        /// </summary>");
            CodeBuilder.AppendLine("        /// <returns></returns>");
            CodeBuilder.AppendLine("        public ActionResult {0}()", this.Table.ViewListName);
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("            {0} search = new {0}",this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("            {");

            int index = 0;
            List<FieldInfo> appendKeys = new List<FieldInfo>();
            foreach (FieldInfo field in Table.Fields)
            {
                index++;
                if (!tableAddin.IsSearchField(field.FieldName))
                    continue;
                appendKeys.Add(field);
            }

            index = 0;
            foreach (FieldInfo field in appendKeys)
            {
                index++;
                FieldInfoAddin addin = tableAddin.FindFieldAddin(field.FieldName);
                if (addin!=null)
                    CodeBuilder.AppendLine("                // {0}", addin.DisplayName);
                if (index < appendKeys.Count)
                {
                    CodeBuilder.AppendLine("                {0} = {1},", field.FieldName, field.GetDefaultValue(true));
                }
                else
                    CodeBuilder.AppendLine("                {0} = {1} ", field.FieldName, field.GetDefaultValue(true));
            }


            CodeBuilder.AppendLine("            };");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            Session[\"{0}\"] = search;", this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            return View(search);");
            CodeBuilder.AppendLine("        }");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        [HttpPost]");
            CodeBuilder.AppendLine("        public ActionResult {0}({1} search)", this.Table.ViewListName, this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("            Session[\"{0}\"] = search;", this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("            return View(search);");
            CodeBuilder.AppendLine("        }");
        }

        private void CreateListPart02()
        {
            var res = from s in this.Connection.Relations
                      where
                          String.Compare(s.ForeignTable.TableName.ToLower(), this.Table.TableName.ToLower(), StringComparison.Ordinal) == 0
                      select s;

            TableInfoAddin tableAddin = this.Connection.FindTableAddin(this.Table.TableName);
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        /// <summary>");
            CodeBuilder.AppendLine("        /// {0}一覧データ取得", tableAddin.TableDisplayName);
            CodeBuilder.AppendLine("        /// </summary>");
            CodeBuilder.AppendLine("        /// <param name=\"sidx\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"sord\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"page\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"rows\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"_search\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"searchField\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"searchOper\"></param>");
            CodeBuilder.AppendLine("        /// <param name=\"searchString\"></param>");
            CodeBuilder.AppendLine("        /// <returns></returns>");
            CodeBuilder.AppendLine("        public ActionResult LoadjqData(string sidx, string sord, int page, int rows,");
            CodeBuilder.AppendLine("                bool _search, string searchField, string searchOper, string searchString)");
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("            {0} search = ({0})Session[\"{0}\"];", this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("            List<{0}> list = {1}.SearchData(search);",this.Table.ModelListName,this.Table.ModelListRepositoryName);
            CodeBuilder.AppendLine("            var listData = list.AsQueryable();");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            // If search, filter the list against the search condition.");
            CodeBuilder.AppendLine("            // Only \"contains\" search is implemented here.");
            CodeBuilder.AppendLine("            var filteredData = listData;");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            // Sort the student list");
            CodeBuilder.AppendLine("            var sortedData = SortIQueryable<{0}>(filteredData, sidx, sord);", this.Table.ModelListName);
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            // Calculate the total number of pages");
            CodeBuilder.AppendLine("            var totalRecords = filteredData.Count();");
            CodeBuilder.AppendLine("            var totalPages = (int)Math.Ceiling((double)totalRecords / (double)rows);");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            // Prepare the data to fit the requirement of jQGrid");
            CodeBuilder.AppendLine("            var data = (from s in sortedData");
            CodeBuilder.AppendLine("                        select new");
            CodeBuilder.AppendLine("                        {");
            CodeBuilder.AppendLine("                            id = s.{0},",this.Table.GetKeyField().FieldName);
            CodeBuilder.AppendLine("                            cell = new object[] ");
            CodeBuilder.AppendLine("                            { ");


            int index = 0;
            List<FieldInfo> appendKeys = new List<FieldInfo>();
            foreach (FieldInfo field in Table.Fields)
            {
                index++;
                if (!tableAddin.IsListField(field.FieldName))
                    continue;
                appendKeys.Add(field);
            }

            index = 0;
            foreach (var r in res)
            {
                index++;
                if (!tableAddin.IsListField(r.ForeignTable.KeyFieldName))
                    continue;

                TableInfo tTable = this.Connection.FindTable(r.PrimaryTable.TableName);
                FieldInfo tField = tTable.FindField(r.PrimaryTable.ValueFieldName);
                appendKeys.Add(tField);
            }



            index = 0;
            foreach (FieldInfo field in appendKeys)
            {
                index++;
                //FieldInfoAddin addin = tableAddin.FindFieldAddin(field.FieldName);

                if (index < appendKeys.Count)
                    CodeBuilder.AppendLine("                                s.{0},",field.FieldName);
                else
                    CodeBuilder.AppendLine("                                s.{0} ", field.FieldName);
            }

            CodeBuilder.AppendLine("                            }");
            CodeBuilder.AppendLine("                        }).ToArray();");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            // Send the data to the jQGrid");
            CodeBuilder.AppendLine("            var jsonData = new");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                total = totalPages,");
            CodeBuilder.AppendLine("                page = page,");
            CodeBuilder.AppendLine("                records = totalRecords,");
            CodeBuilder.AppendLine("                rows = data.Skip((page - 1) * rows).Take(rows)");
            CodeBuilder.AppendLine("            };");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            return Json(jsonData, JsonRequestBehavior.AllowGet);");
            CodeBuilder.AppendLine("        }");
            CodeBuilder.AppendLine("");
        }

        private void CreateListPart03()
        {
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        // Utility method to sort IQueryable given a field name as \"string\"");
            CodeBuilder.AppendLine("        // May consider to put in a cental place to be shared");
            CodeBuilder.AppendLine("        private IQueryable<T> SortIQueryable<T>(IQueryable<T> data, string fieldName, string sortOrder)");
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("            if (string.IsNullOrWhiteSpace(fieldName)) return data;");
            CodeBuilder.AppendLine("            if (string.IsNullOrWhiteSpace(sortOrder)) return data;");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            var param = Expression.Parameter(typeof(T), \"i\");");
            CodeBuilder.AppendLine("            Expression conversion = Expression.Convert(Expression.Property(param, fieldName), typeof(object));");
            CodeBuilder.AppendLine("            var mySortExpression = Expression.Lambda<Func<T, object>>(conversion, param);");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            return (sortOrder == \"desc\") ? data.OrderByDescending(mySortExpression)");
            CodeBuilder.AppendLine("                : data.OrderBy(mySortExpression);");
            CodeBuilder.AppendLine("        }");
            CodeBuilder.AppendLine("");
        }

        private void CreateListPart04()
        {
            CodeBuilder.AppendLine("        [HttpPost]");
            CodeBuilder.AppendLine("        public ActionResult PostExecOrderjqData(object items)");
            CodeBuilder.AppendLine("        {{");
            CodeBuilder.AppendLine("            {0} search = Session[\"{0}\"] as {0};", this.Table.ModelListSearchName);
            CodeBuilder.AppendLine("            var strings = items as string[];");
            CodeBuilder.AppendLine("            if (strings != null) {0}.UpdateOrder(search,(items as string[])[0], Session);", this.Table.ModelListRepositoryName);
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            return null;");
            CodeBuilder.AppendLine("        }}");

        }

        #endregion

        #region EditPart

        private void CreateEditPart()
        {
            CodeBuilder.AppendLine("        #region {0}", this.Table.ViewEditName);
            CreateEditPart01();
            CreateEditPart02();
            CreateEditPart03();
            CreateEditPart04();
            CodeBuilder.AppendLine("        #endregion");

        }

        private void CreateEditPart01()
        {
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        [Authorize]");
            CodeBuilder.AppendLine("        public ActionResult {0}(int id) ",this.Table.ViewEditName);
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            {0} model = {1}.CreateModel(id);",this.Table.ModelEditName,this.Table.ModelEditRepositoryName);
            CodeBuilder.AppendLine("            Session[\"{0}\"] = model;", this.Table.ModelEditName);
            CodeBuilder.AppendLine("            return View(model);");
            CodeBuilder.AppendLine("        }");

        }

        private void CreateEditPart02()
        {
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("        [HttpPost]");
            CodeBuilder.AppendLine("        public ActionResult {0}({1} request) ",this.Table.ViewEditName,this.Table.ModelEditName);
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("            string name = request.btnName;");
            CodeBuilder.AppendLine("            if ( string.IsNullOrEmpty(name) || name == \"戻る\")");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                return RedirectToAction(\"{0}\", \"{1}\");", this.Table.ViewListName, this.Table.EntityName);
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            if (Session[SessionKeys.Login.LoginID] == null ||");
            CodeBuilder.AppendLine("                Session[SessionKeys.Login.UserName] == null ||");
            CodeBuilder.AppendLine("               Session[SessionKeys.Login.UserRole] == null)");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                return RedirectToAction(\"LogOn\", \"Account\");");
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            int login = Converts.ToTryInt(Session[SessionKeys.Login.LoginID]);");
            CodeBuilder.AppendLine("            int roll = Converts.ToTryInt(Session[SessionKeys.Login.UserRole]);");
            CodeBuilder.AppendLine("            string userName = Converts.ToTryString(Session[SessionKeys.Login.UserName]);");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            if (Session[\"{0}\"] == null)",this.Table.ModelEditName);
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                int id = string.IsNullOrEmpty(Request[\"id\"]) ? 0 : Convert.ToInt32(Request[\"id\"]);");
            CodeBuilder.AppendLine("                Session[\"{0}\"] = {1}.CreateModel(id);",this.Table.ModelEditName,this.Table.ModelEditRepositoryName);
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            {0} model = ({0})Session[\"{0}\"];", this.Table.ModelEditName);
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            if (  name == \"一時保存\" || name == \"仮登録\")");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                //基本情報を設定する");
            CodeBuilder.AppendLine("                _SetBaseInfo(request, model);");
            CodeBuilder.AppendLine("                //Viewからデータを設定する");
            CodeBuilder.AppendLine("                _SetViewFromDataInfo(request, model);");
            CodeBuilder.AppendLine("                ");
            CodeBuilder.AppendLine("                // 一時保存処理");
            if (this.Table.IsMasterTable && this.Table.FindField("DataStatus")!=null )
                CodeBuilder.AppendLine("                request.DataStatus = 1;");
            CodeBuilder.AppendLine("                {0}.DataUpdate(request);", this.Table.ModelEditRepositoryName);
            CodeBuilder.AppendLine("                return RedirectToAction(\"{0}\", \"{1}\");", this.Table.ViewListName, this.Table.EntityName);
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("            else if ( name == \"登録\") ");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                //基本情報を設定する");
            CodeBuilder.AppendLine("                _SetBaseInfo(request, model);");
            CodeBuilder.AppendLine("                //Viewからデータを設定する");
            CodeBuilder.AppendLine("                _SetViewFromDataInfo(request, model);");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("                if (ModelState.IsValid && {0}.CheckInput(request, ModelState))",this.Table.ModelEditRepositoryName);
            CodeBuilder.AppendLine("                { ");
            if (this.Table.IsMasterTable && this.Table.FindField("DataStatus") != null)
                CodeBuilder.AppendLine("                    request.DataStatus = 2;");
            CodeBuilder.AppendLine("                    {0}.DataUpdate(request);", this.Table.ModelEditRepositoryName);
            CodeBuilder.AppendLine("                return RedirectToAction(\"{0}\", \"{1}\");", this.Table.ViewListName, this.Table.EntityName);
            CodeBuilder.AppendLine("                }");
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("            else if ( name == \"コピーして作成\")");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                //基本情報を設定する");
            CodeBuilder.AppendLine("                _SetBaseInfo(request, model);");
            CodeBuilder.AppendLine("                //Viewからデータを設定する");
            CodeBuilder.AppendLine("                _SetViewFromDataInfo(request, model);");
            CodeBuilder.AppendLine("                request.{0} = 0;",this.Table.GetKeyField().FieldName);
            CodeBuilder.AppendLine("                ModelState.Clear();");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            }");
            CodeBuilder.AppendLine("            else");
            CodeBuilder.AppendLine("            {");
            CodeBuilder.AppendLine("                //基本情報を設定する");
            CodeBuilder.AppendLine("                _SetBaseInfo(request, model);");
            CodeBuilder.AppendLine("                //Viewからデータを設定する");
            CodeBuilder.AppendLine("                _SetViewFromDataInfo(request, model);");
            CodeBuilder.AppendLine("            }          ");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            Session[\"{0}\"] = request;",this.Table.ModelEditName);
            CodeBuilder.AppendLine("            return View(request);");
            CodeBuilder.AppendLine("        }");

        }

        private void CreateEditPart03()
        {

            var res = from s in this.Connection.Relations
                      where
                          String.Compare(s.ForeignTable.TableName.ToLower(), this.Table.TableName.ToLower(), StringComparison.Ordinal) == 0
                      select s;

            CodeBuilder.AppendLine("        private void _SetBaseInfo({0} request, {0} model) ",this.Table.ModelEditName);
            CodeBuilder.AppendLine("        {");
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("            request.{0} = model.{0};",this.Table.GetKeyField().FieldName);
            CodeBuilder.AppendLine("            // コンボ設定");
            foreach (var r in res)
            {
                TableInfo t = Connection.FindTable(r.PrimaryTable.TableName);
                if (this.Table.FindField(r.PrimaryTable.KeyFieldName) != null)
                    CodeBuilder.AppendLine("            request.{0} = model.{0};",t.EntityListName);
                else
                    CodeBuilder.AppendLine("            //request.{0} = model.{0};", t.EntityListName);
            }
            if (this.Table.IsMasterTable && this.Table.FindField("DataStatus") != null)
                CodeBuilder.AppendLine("            request.DataStatus = model.DataStatus;");
            CodeBuilder.AppendLine("        }");
        }

        private void CreateEditPart04()
        {
            CodeBuilder.AppendLine("        private void _SetViewFromDataInfo({0} request, {0} model)", this.Table.ModelEditName);
            CodeBuilder.AppendLine("        {");
            
            var res = from s in this.Connection.Relations
                      where
                          String.Compare(s.ForeignTable.TableName.ToLower(), this.Table.TableName.ToLower(), StringComparison.Ordinal) == 0
                      select s;
            foreach (var r in res)
            {
                TableInfo t = Connection.FindTable(r.PrimaryTable.TableName);
                if (this.Table.FindField(r.PrimaryTable.ValueFieldName) != null)
                    CodeBuilder.AppendLine("            request.{0} = request.{1}.Find(item => {{ return item.Value == request.{2}.ToString(); }}).Text;",r.PrimaryTable.ValueFieldName,t.EntityListName,r.ForeignTable.KeyFieldName);
                else
                    CodeBuilder.AppendLine("            //request.{0} = request.{1}.Find(item => {{ return item.Value == request.{2}.ToString(); }}).Text;", r.PrimaryTable.ValueFieldName, t.EntityListName, r.ForeignTable.KeyFieldName);
            }
            CodeBuilder.AppendLine("        }");
        }



        #endregion















        protected override void AppendUsing()
        {
            CodeBuilder.AppendLine("using System;");
            CodeBuilder.AppendLine("using System.Collections.Generic;");
            CodeBuilder.AppendLine("using System.Linq;");
            CodeBuilder.AppendLine("using System.Web;");
            CodeBuilder.AppendLine("using System.Web.Mvc;");
            CodeBuilder.AppendLine("using System.Web.Configuration;");
            CodeBuilder.AppendLine("using MvcApplication.Models;");
            CodeBuilder.AppendLine("using System.Linq.Expressions;");
            CodeBuilder.AppendLine("using PacificSystem.Utility;");
            CodeBuilder.AppendLine("using PacificSystem.ConstantLibrary;");
            //CodeBuilder.AppendLine("using PacificSystem.ConstantLibrary.Sessions;");
            CodeBuilder.AppendLine("using PacificSystem.CommunicationLibrary;");
        }

        protected override  void AppandClassStart(string classAdditional, string baseClassName, string functionDesc)
        {
            CodeBuilder.AppendLine("    /// <summary>");
            CodeBuilder.AppendLine("    /// {0}", functionDesc); // 
            CodeBuilder.AppendLine("    /// </summary>");
            CodeBuilder.AppendLine("    [Authorize]");
            if (baseClassName.Trim().Length > 0)
            {
                CodeBuilder.AppendLine("    public partial class {0}{1}:{2} ", this.Table.EntityName, classAdditional, baseClassName);
            }
            else
            {
                CodeBuilder.AppendLine("    public partial class {0}{1} ", this.Table.EntityName, classAdditional);
            }

            SaveFileName = string.Format("{0}{1}", this.Table.EntityName, classAdditional);
            CodeBuilder.AppendLine("    {");

        }

        protected override void AppendNameSpaceStart()
        {
            CodeBuilder.AppendLine("");
            CodeBuilder.AppendLine("namespace MvcApplication.Controllers");
            CodeBuilder.AppendLine("{");
        }


    }
}
